﻿using System;
using System.Activities;
using Microsoft.Activities;
using Reactor.Environment;
using Reactor.Messages.Commands.Core;
using Reactor.Messages.Exceptions;
using Reactor.Messaging;
using Reactor.Messaging.Attributes;
using Reactor.Messaging.Exceptions;
using Reactor.Providers;
using Reactor.ServiceGrid;
using Reactor.ServiceGrid.Repositories;
using Reactor.ServiceGrid.ServiceEntities;
using Reactor.ServiceGrid.Workflows;
using Reactor.Workflow.Persistence;

namespace Reactor.CoreHost.Handlers
{
    [PointToPointChannel]
    public class AdoptServiceCommandHandler : MessageHandlerBase<AdoptService>
    {
        public override void OnHandling(AdoptService message, IMessageContext messageContext)
        {
            // Make sure this handler is loaded only by ReactorCore instances
            ValidateMessage(message);

            // Obtain core instance
            ReactorCore core = GetCore(message);

            // Because this message type is known to be both a workflow message and stand-alone, 
            //  we must determine whether to process this as part of a workflow or directly.
            if (messageContext.WorkflowInstanceId != Guid.Empty)
            {
                if(Log.IsDebugEnabled) Log.DebugFormat("Received AdoptService command is being passed into existing workflow instance as part of an overall TransferService process. Workflow instance id: {0}", messageContext.WorkflowInstanceId);

                // Handle as part of an existing workflow instance
                core.ResumeServiceTransfer(message, messageContext.WorkflowInstanceId);
            }
            else
            {
                // Handle directly
                var serviceIdentifier = new ServiceIdentifier
                {
                    Name = message.ServiceName,
                    Version = new Version(message.ServiceVersion)
                };
                core.AdoptService(serviceIdentifier);
            }   
        }

        private static void ValidateMessage(AdoptService message)
        {
            if (!(Context.GridContext.CurrentReactorService is ReactorCore))
                throw new InvalidOperationException(ServiceGrid.Resources.CommandFailure_NonCoresCannotAdoptServices);

            // Validate message content
            if (string.IsNullOrEmpty(message.ServiceName))
                throw new MessageValidationException("ServiceName cannot be null or empty.");

            if (message.ServiceVersion == null)
                throw new MessageValidationException("ServiceVersion cannot be null.");
        }

        private static ReactorCore GetCore(AdoptService message)
        {
            var core = (ReactorCore)Context.GridContext.CurrentReactorService;

            // Make sure this command was truly destined for this core
            if (core.Identifier.Name != message.CoreName)
                throw new InvalidOperationException();
            return core;
        }
    }
}
